home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / C Internet Config / Examples ƒ / Example / IC Resource ƒ / IC Link In.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-06  |  37.0 KB  |  1,688 lines  |  [TEXT/SPM ]

  1. /*
  2.     IC Link In.c
  3.     
  4.     Main code for accessing the configuration file.  This code can be linked in to an application
  5.     (if the component is not available) to provide access to the IC prefs file.
  6.     
  7.     This code represents the lowest-level of access to the config file.
  8.     
  9.     History
  10.         11/06/95 dhn - Started C port.
  11. */
  12.  
  13. /*
  14.     Original pascal comment:
  15.     
  16.         (* File:         ICLinkIn.p
  17.          * Generated by: 1.0d4
  18.          * For:          IC 1.2
  19.          * On:           Monday, 25 September 1995, 19:28:12
  20.          * 
  21.          * This file is part of the Internet Configuration system and
  22.          * is placed in the public domain for the benefit of all.
  23.          *)
  24. */
  25.  
  26. #include <Components.h>
  27. #include <AppleTalk.h>
  28. #include <Folders.h>
  29. #include <Processes.h>
  30. #include <Errors.h>
  31. #include <AppleEvents.h>
  32. #include <LowMem.h>
  33.  
  34. #include "IC Types.h"
  35. #include "IC Keys.h"
  36.  
  37. #include "IC Resource API.h"
  38. #include "IC Link In Subs.h"
  39.  
  40. #define kICOurManufacturer    'JPQE'
  41. #define kRes_Code            'ICRP'
  42.  
  43. // Local Prototypes
  44. #ifdef __cplusplus
  45. extern "C" {
  46. #endif
  47.  
  48. OSErr ICFindFolder(short vRefNum,OSType folderType,Boolean createFolder,short* foundVRefNum,long* foundDirID);
  49. Boolean ICRCloseIfOpen(ICRRecordPtr inst);
  50. ICError ValidDirSpec(ICDirSpec* folder);
  51. OSErr FoundFile(ICDirSpec* folder,short ndx,FSSpec* found_file);
  52. Boolean ScanFolder(ICRRecordPtr inst,ICDirSpec* folder,FSSpecPtr found_file);
  53. OSErr FindPrefFolder(ICDirSpec* pref_fold);
  54. void SetSFCWD(ICRRecordPtr inst);
  55. ICError GetFile(ICRRecordPtr inst,FSSpecPtr fs);
  56. ICError PutFile(ICRRecord* inst,FSSpecPtr fs);
  57. short ICRPermToFSPerm(ICPerm perm);
  58. ICError ICRCheckInside(ICRRecord* inst);
  59. ICError ICRForceInside(ICRRecord* inst,ICPerm perm,Boolean* force_info);
  60. ICError ICRReleaseInside(ICRRecord* inst,Boolean force_info);
  61. Boolean __URL_SpecStartChar(char ch);
  62. Boolean __URL_SpecEndChar(char ch);
  63. ICError ExpandSelection(char* datap,long len,long* selStart,long* selEnd);
  64. Boolean SpaceTab(char ch);
  65. Boolean SpaceTabRet(char ch);
  66. ICError ShrinkSelection(char* datap,long len,long* selStart,long* selEnd);
  67. ICError StripReturns(Handle urlh);
  68. void UnpackCopyString(Ptr* p,StringPtr s);
  69. OSErr UnpackEntry(Handle entries,long pos,ICMapEntry* entry,long* user_length);
  70. OSErr FastGetEntry(Handle entries,long pos,ICMapEntry* entry);
  71. void PackCopyString(ICMapEntry* entry,Ptr p,StringPtr s);
  72. void PackEntry(ICMapEntry* entry,Ptr p,long user_length);
  73. short GetShort(Ptr P);
  74. char UpCase(char ch);
  75. Boolean IsExtensionVar(StringPtr name,StringPtr ext);
  76.  
  77. Boolean HasResourceFork(const FSSpec* file);
  78. OSErr EnsureResourceFork(const FSSpec* file);
  79.  
  80. #ifdef __cplusplus
  81. }
  82. #endif
  83.  
  84. /*
  85.     HasResourceFork
  86.     EnsureResourceFork
  87.     
  88.     The IC pieces have one bug (that I have found).  Although they ensure that a file exists when selecting one
  89.     (either through the Find, FindUser, FindGeneral, or SpecifyConfigFile routines), they don't ensure that the
  90.     files have a resource fork.  That means that whatever piece is specifying the file *must* get everything right.
  91.     
  92.     HasResourceFork and EnsureResourceFork will check the config file; if it has a resource fork, nothing is done.
  93.     If the file doesn't have a resource fork, one will be added.
  94. */
  95. Boolean HasResourceFork(const FSSpec* spec){
  96.     HParamBlockRec pbr;
  97.     OSErr err;
  98.     
  99.     pbr.fileParam.ioCompletion=0;
  100.     pbr.fileParam.ioVRefNum=spec->vRefNum;
  101.     pbr.fileParam.ioFDirIndex=0;
  102.     pbr.fileParam.ioNamePtr=(StringPtr)spec->name;
  103.     pbr.fileParam.ioDirID=spec->parID;
  104.     
  105.     err=PBHGetFInfo(&pbr,false);
  106.     if (err!=noErr)
  107.         return false;
  108.     
  109.     /*
  110.         If a file has a resource fork, even an empty one, a resource map will still exist for the file,
  111.         therefore the ioFlRLgLen (which contains the length of the resource fork) will be some number
  112.         greater than zero if the file has a resource fork.
  113.     */
  114.     return (pbr.fileParam.ioFlRLgLen>0);
  115. }
  116.  
  117. OSErr EnsureResourceFork(const FSSpec* spec){
  118.     HParamBlockRec pbr;
  119.     OSErr err;
  120.     
  121.     pbr.fileParam.ioCompletion=0;
  122.     pbr.fileParam.ioVRefNum=spec->vRefNum;
  123.     pbr.fileParam.ioFDirIndex=0;
  124.     pbr.fileParam.ioNamePtr=(StringPtr)spec->name;
  125.     pbr.fileParam.ioDirID=spec->parID;
  126.     
  127.     err=PBHGetFInfo(&pbr,false);
  128.     
  129.     if (err==fnfErr){
  130.         // then the file doesn't exist, but is being put in a default place so it really should be there
  131.     } else if (err!=noErr)
  132.         return err;
  133.     
  134.     if (pbr.fileParam.ioFlRLgLen<=0){
  135.         // file doesn't have a resource fork, create one for the file
  136.         HCreateResFile(spec->vRefNum,spec->parID,spec->name);
  137.         return ResError();
  138.     }
  139.     return noErr;
  140. }
  141.  
  142. /*
  143.     ICFindFolder
  144.     
  145.     converted from the pascal wrapper function to call the FindFolder trap.
  146.     
  147.     Was declared as:
  148.         
  149.         inline $7000,$A823
  150. */
  151. OSErr ICFindFolder(short vRefNum,OSType folderType,Boolean createFolder,short* foundVRefNum,long* foundDirID){
  152.     return FindFolder(vRefNum,folderType,createFolder,foundVRefNum,foundDirID);
  153. }
  154.  
  155. ICError ICRStart(ICRRecordPtr inst,OSType creator){
  156.     ICError err;
  157.     Str255 defPrompt="\pCreate configuration as:";
  158.     
  159.     if (inst==(ICRRecordPtr)0)
  160.         return (ICError)paramErr;
  161.     
  162.     inst->have_config_file=false;
  163.     inst->config_file.vRefNum=0;
  164.     inst->config_file.parID=0;
  165.     inst->config_file.name[0]=0;
  166.     inst->config_refnum=0;
  167.     inst->perm=icNoPerm;
  168.     
  169.     BlockMoveData((Ptr)defPrompt,(Ptr)inst->prompt,defPrompt[0]+2);
  170.     
  171.     ICRDefaultFileName(inst,inst->default_filename);
  172.     
  173.     return noErr;
  174. }
  175.  
  176. Boolean ICRCloseIfOpen(ICRRecordPtr inst){
  177.     Boolean ret=inst->perm!=icNoPerm;
  178.     
  179.     if (inst->config_refnum!=0){
  180.         CloseResFile(inst->config_refnum);
  181.         inst->config_refnum=0;
  182.     }
  183.     
  184.     inst->perm=icNoPerm;
  185.     
  186.     return ret;
  187. }
  188.  
  189. ICError ICRStop(ICRRecordPtr inst){
  190.     
  191.     if (inst==(ICRRecordPtr)0)
  192.         return (ICError)paramErr;
  193.     
  194.     if (ICRCloseIfOpen(inst))
  195.         return (ICError)paramErr;
  196.     
  197.     return (ICError)noErr;
  198. }
  199.  
  200.  
  201. ICError ValidDirSpec(ICDirSpec* folder){
  202.     CInfoPBRec cpb;
  203.     
  204.     cpb.hFileInfo.ioVRefNum=folder->vRefNum;
  205.     cpb.hFileInfo.ioDirID=folder->dirID;
  206.     cpb.hFileInfo.ioNamePtr=(StringPtr)0;
  207.     cpb.hFileInfo.ioFDirIndex=-1;
  208.     
  209.     return (ICError)PBGetCatInfoSync(&cpb);
  210. }
  211.  
  212. OSErr FoundFile(ICDirSpec* folder,short ndx,FSSpec* found_file){
  213.     OSErr err;
  214.     CInfoPBRec cpb;
  215.     Boolean is_folder;
  216.     Boolean was_alias;
  217.     long response;
  218.     
  219.     cpb.hFileInfo.ioVRefNum=folder->vRefNum;
  220.     cpb.hFileInfo.ioDirID=folder->dirID;
  221.     cpb.hFileInfo.ioNamePtr=found_file->name;
  222.     cpb.hFileInfo.ioFDirIndex=ndx;
  223.     
  224.     err=PBGetCatInfoSync(&cpb);
  225.     
  226.     if (err==noErr){
  227.         found_file->vRefNum=cpb.hFileInfo.ioVRefNum;
  228.         found_file->parID=cpb.hFileInfo.ioFlParID;
  229.         
  230.         if ((cpb.hFileInfo.ioFlAttrib&(16))||(cpb.hFileInfo.ioFlFndrInfo.fdType!=kICFileType)){
  231.             err=(OSErr)1;
  232.         } else if ((Gestalt(gestaltAliasMgrAttr,&response)==noErr)&&(BitTst(&response,(31-gestaltAliasMgrPresent)))){
  233.             err=ResolveAliasFile(found_file,true,&is_folder,&was_alias);
  234.             
  235.             if (err!=noErr)
  236.                 err=(OSErr)1;
  237.         }
  238.     }
  239.     
  240.     return err;
  241. }
  242.  
  243. Boolean ScanFolder(ICRRecordPtr inst,ICDirSpec* folder,FSSpecPtr found_file){
  244.     ICError err;
  245.     Boolean found;
  246.     register short i;
  247.     
  248.     BlockMoveData((Ptr)inst->default_filename,(Ptr)found_file->name,inst->default_filename[0]+1);
  249.     
  250.     found=(FoundFile(folder,0,found_file)==noErr);
  251.     
  252.     if (!found){
  253.         i=1;
  254.         
  255.         do {
  256.             found_file->name[0]=0;
  257.             err=FoundFile(folder,i,found_file);
  258.             i++;
  259.         } while (err!=1);
  260.         
  261.         found=(err==noErr);
  262.     }
  263.     
  264.     return found;
  265. }
  266.  
  267. ICError ICRFindConfigFile(ICRRecordPtr inst,short count,ICDirSpecArrayPtr folders){
  268.     return ICRGeneralFindConfigFile(inst,true,true,count,folders);
  269. }
  270.  
  271. ICError ICRFindUserConfigFile(ICRRecordPtr inst,ICDirSpec* where){
  272.     return ICRGeneralFindConfigFile(inst,false,true,1,where);
  273. }
  274.  
  275. OSErr FindPrefFolder(ICDirSpec* pref_fold){
  276.     OSErr err;
  277.     SysEnvRec env;
  278.     long response;
  279.     
  280.     err=Gestalt(gestaltFindFolderAttr,&response);
  281.     
  282.     if (err==noErr){
  283.         if (BitTst(&response,(31-gestaltFindFolderPresent)))
  284.             return ICFindFolder(kOnSystemDisk,kPreferencesFolderType,true,&(pref_fold->vRefNum),&(pref_fold->dirID));
  285.     }
  286.     
  287.     // otherwise simulate FindFolder
  288.     
  289.     err=SysEnvirons(curSysEnvVers,&env);
  290.     
  291.     if (err==noErr)
  292.         err=GetWDInfo(env.sysVRefNum,&(pref_fold->vRefNum),&(pref_fold->dirID),&response);
  293.     
  294.     return err;
  295. }
  296.  
  297. ICError ICRGeneralFindConfigFile(ICRRecordPtr inst,Boolean search_prefs,Boolean can_create,short count,ICDirSpecArrayPtr folders){
  298.     ICError err=noErr;
  299.     register short i=0;
  300.     Boolean found=false;
  301.     ICDirSpec pref_fold;
  302.     ICDirSpec* last_folder_scanned;
  303.     FSSpec temp_config_file;
  304.     HParamBlockRec pbr;
  305.     
  306.     inst->have_config_file=false;
  307.     
  308.     if (inst->perm!=icNoPerm)
  309.         return (ICError)paramErr;
  310.     
  311.     if ((count<0)||((count!=0)&&(folders==(ICDirSpecArrayPtr)0)))
  312.         return (ICError)paramErr;
  313.     
  314.     if ((count==0)&&(!search_prefs)&&(can_create))
  315.         return (ICError)paramErr;
  316.     
  317.     i=0;
  318.     while ((err==noErr)&&(i<count)){
  319.         err=ValidDirSpec(&(folders[i]));
  320.         i++;
  321.     }
  322.     
  323.     if (err!=noErr)
  324.         return err;
  325.     
  326.     i=0;
  327.     
  328.     while ((i<count)&&(!found)){
  329.         found=ScanFolder(inst,&(folders[i]),&temp_config_file);
  330.         
  331.         last_folder_scanned=&(folders[i]);
  332.         i++;
  333.     }
  334.     
  335.     if ((!found)&&(search_prefs)){
  336.         err=FindPrefFolder(&pref_fold);
  337.         
  338.         if (err==noErr){
  339.             found=ScanFolder(inst,&pref_fold,&temp_config_file);
  340.             last_folder_scanned=&pref_fold;
  341.         }
  342.     }
  343.     
  344.     if ((!found)&&(can_create)){
  345.         temp_config_file.vRefNum=last_folder_scanned->vRefNum;
  346.         temp_config_file.parID=last_folder_scanned->dirID;
  347.         BlockMoveData((Ptr)inst->default_filename,(Ptr)temp_config_file.name,inst->default_filename[0]+1);
  348.         found=true;
  349.     }
  350.     
  351.     if (!found)
  352.         err=icConfigNotFoundErr;
  353.     
  354.     if (err==noErr){
  355.         BlockMoveData((Ptr)&(temp_config_file),(Ptr)&(inst->config_file),sizeof(FSSpec));
  356.         inst->have_config_file=true;
  357.         
  358.         // Need to ensure that there is a resource fork for a file...
  359.         err=EnsureResourceFork(&(inst->config_file));
  360.     }
  361.     
  362.     return err;
  363. }
  364.  
  365. void SetSFCWD(ICRRecordPtr inst){
  366.     
  367.     if (inst->have_config_file){
  368.         LMSetCurDirStore(inst->config_file.parID);
  369.         LMSetSFSaveDisk(-(inst->config_file.vRefNum));
  370.     }
  371. }
  372.  
  373. ICError GetFile(ICRRecordPtr inst,FSSpecPtr fs){
  374.     ICError err=userCanceledErr;
  375.     SFTypeList typeList;
  376.     StandardFileReply nreply;
  377.     SFReply oreply;
  378.     long eric;
  379.     Point where;
  380.     
  381.     SetSFCWD(inst);
  382.     
  383.     typeList[0]=kICFileType;
  384.     
  385.     if (HaveNewStandardFile()){
  386.         StandardGetFile((FileFilterUPP)0,1,typeList,&nreply);
  387.         if (nreply.sfGood){
  388.             BlockMoveData((Ptr)&(nreply.sfFile),fs,sizeof(FSSpec));
  389.             err=noErr;
  390.         }
  391.     } else {
  392.         where.h=0x40;
  393.         where.v=0x40;
  394.         
  395.         SFGetFile(where,"\p",(FileFilterUPP)0,1,typeList,(DlgHookUPP)0,&oreply);
  396.         if (oreply.good){
  397.             err=GetWDInfo(oreply.vRefNum,&fs->vRefNum,&fs->parID,&eric);
  398.             BlockMoveData(oreply.fName,fs->name,oreply.fName[0]+1);
  399.         }
  400.     }
  401.     
  402.     return err;
  403. }
  404.  
  405. ICError PutFile(ICRRecord* inst,FSSpecPtr fs){
  406.     ICError err;
  407.     SFTypeList typeList;
  408.     StandardFileReply nreply;
  409.     SFReply oreply;
  410.     long eric;
  411.     Str63 defname;
  412.     
  413.     SetSFCWD(inst);
  414.     err=userCanceledErr;
  415.     typeList[0]=kICFileType;
  416.     
  417.     if (inst->have_config_file){
  418.         BlockMoveData(inst->config_file.name,defname,inst->config_file.name[0]+1);
  419.     } else {
  420.         BlockMoveData(inst->default_filename,defname,inst->default_filename[0]+1);
  421.     }
  422.     
  423.     if (HaveNewStandardFile()){
  424.         StandardPutFile(inst->prompt,defname,&nreply);
  425.         if (nreply.sfGood){
  426.             BlockMoveData((Ptr)&(nreply.sfFile),(Ptr)fs,sizeof(FSSpec));
  427.             err=noErr;
  428.         }
  429.     } else {
  430.         Point where;
  431.         
  432.         where.h=0x040;
  433.         where.v=0x040;
  434.         
  435.         SFPutFile(where,inst->prompt,defname,(DlgHookUPP)0,&oreply);
  436.         if (oreply.good){
  437.             err=GetWDInfo(oreply.vRefNum,&fs->vRefNum,&fs->parID,&eric);
  438.             BlockMoveData(oreply.fName,fs->name,oreply.fName[0]+1);
  439.         }
  440.     }
  441.     
  442.     return err;
  443. }
  444.  
  445. ICError ICRChooseConfig(ICRRecord* inst){
  446.     OSErr err=noErr;
  447.     FSSpec config;
  448.     
  449.     if (inst->perm!=icNoPerm)
  450.         return paramErr;
  451.     
  452.     err=CanInteract();
  453.     
  454.     if (err==noErr){
  455.         err=GetFile(inst,&config);
  456.     }
  457.     
  458.     if (err==noErr){
  459.         err=ICRSpecifyConfigFile(inst,&config);
  460.     }
  461.     
  462.     return err;
  463. }
  464.  
  465. ICError ICRChooseNewConfig(ICRRecord* inst){
  466.     OSErr err=noErr;
  467.     FSSpec config;
  468.     
  469.     if (inst->perm!=icNoPerm)
  470.         return paramErr;
  471.     
  472.     err=CanInteract();
  473.     
  474.     if (err==noErr)
  475.         err=PutFile(inst,&config);
  476.     
  477.     if (err==noErr){
  478.         HDelete(config.vRefNum,config.parID,config.name);
  479.         err=HCreate(config.vRefNum,config.parID,config.name,kICCreator,kICFileType);
  480.     }
  481.     
  482.     if (err==noErr)
  483.         err=ICRSpecifyConfigFile(inst,&config);
  484.     
  485.     return err;
  486. }
  487.  
  488. ICError ICRGetConfigName(ICRRecord* inst,Boolean longname,StringPtr name){
  489.     OSErr err=noErr;
  490.     
  491.     if (!inst->have_config_file)
  492.         return paramErr;
  493.     
  494.     if (!longname){
  495.         BlockMoveData(inst->config_file.name,name,inst->config_file.name[0]+1);
  496.         err=noErr;
  497.     } else {
  498.         err=FSSpecToFullPath(&(inst->config_file),name);
  499.     }
  500.     
  501.     return err;
  502. }
  503.  
  504. ICError ICRGetConfigReference(ICRRecord* inst,ICConfigRefHandle ref){
  505.     ICError err=noErr;
  506.     ICConfigRef header;
  507.     long loe;
  508.     
  509.     if (!inst->have_config_file)
  510.         return paramErr;
  511.     
  512.     if (ref==(ICConfigRefHandle)0)
  513.         return paramErr;
  514.     
  515.     err=FSSpecToICFileSpec(&(inst->config_file),(ICFileSpecHandle)ref);
  516.     
  517.     if (err==noErr){
  518.         header.manufacturer=kICOurManufacturer;
  519.         loe=Munger((Handle)ref,0,(Ptr)0,0,&header,sizeof(ICConfigRef));
  520.         err=MemError();
  521.     }
  522.     
  523.     if (err!=noErr)
  524.         SetHandleSize((Handle)ref,0);
  525.     
  526.     return err;
  527. }
  528.  
  529. ICError ICRSetConfigReference(ICRRecord* inst,ICConfigRefHandle ref,long flags){
  530.     ICError err;
  531.     ICFileSpecHandle filespec;
  532.     long loe;
  533.     FSSpec fs;
  534.     
  535.     if (inst->perm!=icNoPerm)
  536.         return paramErr;
  537.     
  538.     if (ref==(ICConfigRefHandle)0)
  539.         return paramErr;
  540.     
  541.     if (GetHandleSize((Handle)ref)<4)
  542.         return paramErr;
  543.     
  544.     if ((*ref)->manufacturer!=kICOurManufacturer)
  545.         return icConfigInappropriateErr;
  546.     
  547.     if (GetHandleSize((Handle)ref)<(sizeof(ICConfigRef)+sizeof(ICFileSpec)))
  548.         return paramErr;
  549.     
  550.     BlockMoveData((Ptr)ref,(Ptr)&filespec,sizeof(ICFileSpecHandle));
  551.     err=HandToHand((Handle*)(&filespec));
  552.     
  553.     if (err==noErr){
  554.         loe=Munger((Handle)filespec,0,(Ptr)0,sizeof(ICConfigRef),&loe,0);
  555.         err=ICFileSpecToFSSpec(filespec,!(flags&icNoUserInteraction_mask),&fs);
  556.         DisposeHandle((Handle)filespec);
  557.     }
  558.     
  559.     if (err==noErr)
  560.         ICRSpecifyConfigFile(inst,&fs);
  561.     
  562.     return err;
  563. }
  564.  
  565. ICError ICRSpecifyConfigFile(ICRRecord* inst,FSSpecPtr config){
  566.     ICError err;
  567.     ICDirSpec folder;
  568.     
  569.     if (inst->perm!=icNoPerm)
  570.         return paramErr;
  571.     
  572.     folder.vRefNum=config->vRefNum;
  573.     folder.dirID=config->parID;
  574.     
  575.     err=ValidDirSpec(&folder);
  576.     
  577.     if (err==noErr)
  578.         BlockMoveData((Ptr)config,(Ptr)&(inst->config_file),sizeof(FSSpec));
  579.     
  580.     inst->have_config_file=(err==noErr);
  581.     
  582.     if (inst->have_config_file){
  583.         // Need to ensure that there is a resource fork for a file...
  584.         err=EnsureResourceFork(&(inst->config_file));
  585.     }
  586.     
  587.     return err;
  588. }
  589.  
  590. ICError ICRGetSeed(ICRRecord* inst,long* seed){
  591.     ICError err;
  592.     CInfoPBRec cpb;
  593.     
  594.     *seed=0L;
  595.     err=fnfErr;
  596.     
  597.     if (inst->have_config_file){
  598.         cpb.hFileInfo.ioVRefNum=inst->config_file.vRefNum;
  599.         cpb.hFileInfo.ioDirID=inst->config_file.parID;
  600.         cpb.hFileInfo.ioNamePtr=inst->config_file.name;
  601.         cpb.hFileInfo.ioFDirIndex=0;
  602.         
  603.         err=PBGetCatInfoSync(&cpb);
  604.         
  605.         if (err==noErr)
  606.             *seed=cpb.hFileInfo.ioFlMdDat;
  607.         else if (err==fnfErr)
  608.             err=noErr;
  609.     }
  610.     
  611.     return err;
  612. }
  613.  
  614. ICError ICRGetPerm(ICRRecord* inst,ICPerm* perm){
  615.     *perm=inst->perm;
  616.     return noErr;
  617. }
  618.  
  619. short ICRPermToFSPerm(ICPerm perm){
  620.     switch (perm){
  621.         case icReadOnlyPerm:
  622.             return fsRdPerm;
  623.             break;
  624.         case icReadWritePerm:
  625.             return fsRdWrPerm;
  626.             break;
  627.         default:
  628.             return 0;
  629.             break;
  630.     }
  631.     
  632.     return 0;
  633. }
  634.  
  635. ICError ICRBegin(ICRRecord* inst,ICPerm perm){
  636.     ICError err;
  637.     short ref;
  638.     
  639.     if ((inst->perm!=icNoPerm)||(perm==icNoPerm))
  640.         return paramErr;
  641.     
  642.     if (!inst->have_config_file)
  643.         return bdNamErr;
  644.     
  645.     ref=FSpOpenResFile(&(inst->config_file),ICRPermToFSPerm(perm));
  646.     err=ResError();
  647.     
  648.     if ((err==fnfErr)||(err==eofErr)){
  649.         switch (perm){
  650.             case icReadOnlyPerm:
  651.                 ref=0;
  652.                 err=noErr;
  653.                 break;
  654.             case icReadWritePerm:
  655.                 FSpCreate(&(inst->config_file),kICCreator,kICFileType,smSystemScript);
  656.                 FSpCreateResFile(&(inst->config_file),kICCreator,kICFileType,smSystemScript);
  657.                 ref=FSpOpenResFile(&(inst->config_file),ICRPermToFSPerm(perm));
  658.                 err=ResError();
  659.                 break;
  660.         }
  661.     }
  662.     
  663.     if (err==noErr){
  664.         inst->config_refnum=ref;
  665.         inst->perm=perm;
  666.     } else {
  667.         if ((err==opWrErr)||(err==permErr)){
  668.             err=icNoMoreWritersErr;
  669.         }
  670.     }
  671.     
  672.     return err;
  673. }
  674.  
  675. ICError ICRCheckInside(ICRRecord* inst){
  676.     
  677.     if (inst->perm==icNoPerm)
  678.         return paramErr;
  679.     
  680.     return noErr;
  681. }
  682.  
  683. ICError ICRForceInside(ICRRecord* inst,ICPerm perm,Boolean* force_info){
  684.     ICError err;
  685.     
  686.     *force_info=false;
  687.     
  688.     if ((inst->perm==perm)||((inst->perm==icReadWritePerm)&&(perm==icReadOnlyPerm)))
  689.         return noErr;
  690.     else if (inst->perm==icNoPerm){
  691.         err=ICRBegin(inst,perm);
  692.         *force_info=(err==noErr);
  693.     } else
  694.         return icPermErr;
  695.     
  696.     return err;
  697. }
  698.  
  699. ICError ICRReleaseInside(ICRRecord* inst,Boolean force_info){
  700.     if (force_info)
  701.         return ICREnd(inst);
  702.     
  703.     return noErr;
  704. }
  705.  
  706. ICError ICRGetPref(ICRRecord* inst,StringPtr key,ICAttr* attr,Ptr buf,long* size){
  707.     ICError err,err2;
  708.     long max_size=*size;
  709.     long true_size;
  710.     short old_refnum;
  711.     Handle prefh;
  712.     Boolean force_info;
  713.     
  714.     *size=0L;
  715.     *attr=ICattr_no_change;
  716.     prefh=(Handle)0;
  717.     
  718.     err=ICRForceInside(inst,icReadOnlyPerm,&force_info);
  719.     
  720.     if ((err==noErr)&&(inst->config_refnum==0)){
  721.         err=icPrefNotFoundErr;
  722.     }
  723.     
  724.     if ((err==noErr)&&((key[0]==0)||((max_size<0)&&(buf!=(Ptr)0))))
  725.         err=paramErr;
  726.     
  727.     if (err==noErr){
  728.         old_refnum=CurResFile();
  729.         UseResFile(inst->config_refnum);
  730.         err=ResError();
  731.         
  732.         if (err==noErr){
  733.             prefh=Get1NamedResource(kRes_Code,key);
  734.             err=ResError();
  735.             
  736.             if (prefh==(Handle)0)
  737.                 err=icPrefNotFoundErr;
  738.             
  739.             if (err==noErr){
  740.                 true_size=GetHandleSize(prefh);
  741.                 if (true_size<4)
  742.                     err=icPrefDataErr;
  743.             }
  744.             
  745.             if (err==noErr){
  746.                 *size=true_size-4;
  747.                 *attr=**((long**)prefh);
  748.                 
  749.                 if ((buf!=(Ptr)0)&&(*size!=0)){
  750.                     if (*size>max_size)
  751.                         err=icTruncatedErr;
  752.                     else
  753.                         max_size=*size;
  754.                     
  755.                     BlockMoveData((Ptr)((*prefh)+sizeof(long)),buf,max_size);
  756.                 }
  757.             }
  758.             UseResFile(old_refnum);
  759.         }
  760.     }
  761.     
  762.     if (prefh!=(Handle)0)
  763.         ReleaseResource(prefh);
  764.     
  765.     err2=ICRReleaseInside(inst,force_info);
  766.     
  767.     if (err==noErr)
  768.         err=err2;
  769.     
  770.     return err;
  771. }
  772.  
  773. ICError ICRSetPref(ICRRecord* inst,StringPtr key,ICAttr attr,Ptr buf,long size){
  774.     ICError err,err2;
  775.     long old_attr;
  776.     short old_refnum;
  777.     Handle prefh;
  778.     short id;
  779.     Boolean force_info;
  780.     
  781.     prefh=(Handle)0;
  782.     if (buf==(Ptr)0)
  783.         size=0;
  784.     
  785.     err=ICRForceInside(inst,icReadWritePerm,&force_info);
  786.     
  787.     if ((err==noErr)&&(inst->perm!=icReadWritePerm))
  788.         err=icPermErr;
  789.     
  790.     if ((err==noErr)&&(inst->config_refnum==0))
  791.         err=icInternalErr;
  792.     
  793.     if ((err==noErr)&&((key[0]==0)||(size<0)))
  794.         err=paramErr;
  795.     
  796.     if (err==noErr){
  797.         old_refnum=CurResFile();
  798.         UseResFile(inst->config_refnum);
  799.         err=ResError();
  800.         if (err==noErr){
  801.             prefh=Get1NamedResource(kRes_Code,key);
  802.             if ((prefh!=(Handle)0)&&(GetHandleSize(prefh)<4)){
  803.                 RmveResource(prefh);
  804.                 DisposeHandle(prefh);
  805.                 prefh=(Handle)0;
  806.             }
  807.             if (prefh==(Handle)0)
  808.                 old_attr=0;
  809.             else
  810.                 old_attr=**((long**)prefh);
  811.             
  812.             if (attr==ICattr_no_change)
  813.                 attr=old_attr;
  814.             
  815.             if ((old_attr&ICattr_locked_mask)&&(attr&ICattr_locked_mask)&&(buf!=(Ptr)0))
  816.                 err=icPermErr;
  817.             
  818.             if (prefh==(Handle)0){
  819.                 prefh=NewHandle(size+4);
  820.                 err=MemError();
  821.                 
  822.                 if (err==noErr){
  823.                     do {
  824.                         id=Unique1ID(kRes_Code);
  825.                     } while (id<=127);
  826.                     
  827.                     AddResource(prefh,kRes_Code,id,key);
  828.                     err=ResError();
  829.                     
  830.                     if (err!=noErr){
  831.                         DisposeHandle(prefh);
  832.                         prefh=(Handle)0;
  833.                     }
  834.                 }
  835.             }
  836.             if ((err==noErr)&&(buf!=(Ptr)0)){
  837.                 SetHandleSize(prefh,size+4);
  838.                 err=MemError();
  839.             }
  840.             if ((err==noErr)&&(size>0))
  841.                 BlockMoveData(buf,(Ptr)((*prefh)+4),size);
  842.             if (err==noErr){
  843.                 **((long**)prefh)=attr;
  844.                 ChangedResource(prefh);
  845.                 WriteResource(prefh);
  846.                 err=ResError();
  847.             }
  848.             UseResFile(old_refnum);
  849.         }
  850.     }
  851.     
  852.     if (prefh!=(Handle)0)
  853.         ReleaseResource(prefh);
  854.     
  855.     err2=ICRReleaseInside(inst,force_info);
  856.     
  857.     if (err==noErr)
  858.         err=err2;
  859.     
  860.     return err;
  861. }
  862.  
  863. // I call ICRForceInside to speed this routine up.  ICRForceInside will do an ICRBegin and hence open the resource
  864. // file, which is good because otherwise I'd open it twice, once for each ICRGetPref.
  865.  
  866. ICError ICRFindPrefHandle(ICRRecord* inst,StringPtr key,ICAttr* attr,Handle prefh){
  867.     ICError err=noErr,err2=noErr;
  868.     long prefsize=0L;
  869.     Boolean force_info;
  870.     
  871.     if (prefh==(Handle)0)
  872.         err=paramErr;
  873.     
  874.     if (err==noErr){
  875.         err=ICRForceInside(inst,icReadOnlyPerm,&force_info);
  876.         if (err==noErr)
  877.             err=ICRGetPref(inst,key,attr,(Ptr)0,&prefsize);
  878.         
  879.         if (err==noErr){
  880.             SetHandleSize(prefh,prefsize);
  881.             err=MemError();
  882.         }
  883.         
  884.         if (err==noErr){
  885.             HLock(prefh);
  886.             err=ICRGetPref(inst,key,attr,*prefh,&prefsize);
  887.             HUnlock(prefh);
  888.         }
  889.         
  890.         err2=ICRReleaseInside(inst,force_info);
  891.     }
  892.     if (err==noErr)
  893.         err=err2;
  894.     
  895.     if ((prefh!=(Handle)0)&&(err!=noErr)){
  896.         SetHandleSize(prefh,0);
  897.     }
  898.     
  899.     return err;
  900. }
  901.  
  902. ICError ICRGetPrefHandle(ICRRecord* inst,StringPtr key,ICAttr* attr,Handle* prefh){
  903.     ICError err;
  904.     
  905.     *prefh=NewHandle(0);
  906.     err=MemError();
  907.     
  908.     if (err==noErr)
  909.         err=ICRFindPrefHandle(inst,key,attr,*prefh);
  910.     
  911.     if (err==icPrefNotFoundErr){
  912.         SetHandleSize(*prefh,0);
  913.         *attr=0;
  914.         err=noErr;
  915.     }
  916.     
  917.     return err;
  918. }
  919.  
  920. ICError ICRSetPrefHandle(ICRRecord* inst,StringPtr key,ICAttr attr,Handle prefh){
  921.     ICError err=noErr;
  922.     SignedByte s;
  923.     
  924.     if (prefh!=(Handle)0){
  925.         if (*prefh==(Ptr)0)
  926.             err=paramErr;
  927.         if (err==noErr){
  928.             s=HGetState(prefh);
  929.             HLock(prefh);
  930.             err=ICRSetPref(inst,key,attr,*prefh,GetHandleSize(prefh));
  931.             HSetState(prefh,s);
  932.         }
  933.     } else {
  934.         err=ICRSetPref(inst,key,attr,(Ptr)0,0);
  935.     }
  936.     
  937.     return err;
  938. }
  939.  
  940. ICError ICRCountPref(ICRRecord* inst,long* count){
  941.     ICError err;
  942.     short old_refnum;
  943.     
  944.     err=ICRCheckInside(inst);
  945.     if (err==noErr){
  946.         if (inst->config_refnum==0)
  947.             *count=0;
  948.         else {
  949.             old_refnum=CurResFile();
  950.             UseResFile(inst->config_refnum);
  951.             err=ResError();
  952.             if (err==noErr){
  953.                 *count=Count1Resources(kRes_Code);
  954.                 err=ResError();
  955.                 UseResFile(old_refnum);
  956.             }
  957.         }
  958.     }
  959.     
  960.     if (err!=noErr)
  961.         *count=0;
  962.     
  963.     return err;
  964. }
  965.  
  966. ICError ICRGetIndPref(ICRRecord* inst,long n,StringPtr key){
  967.     ICError err;
  968.     short old_refnum;
  969.     Handle prefh=(Handle)0;
  970.     short junk_id;
  971.     ResType junk_type;
  972.     
  973.     err=ICRCheckInside(inst);
  974.     if ((err==noErr)&&(n<1))
  975.         err=paramErr;
  976.     
  977.     if (err==noErr){
  978.         if (inst->config_refnum==0)
  979.             err=icPrefNotFoundErr;
  980.         else {
  981.             old_refnum=CurResFile();
  982.             UseResFile(inst->config_refnum);
  983.             err=ResError();
  984.             if (err==noErr){
  985.                 SetResLoad(false);
  986.                 prefh=Get1IndResource(kRes_Code,n);
  987.                 SetResLoad(true);
  988.                 
  989.                 if (prefh==(Handle)0)
  990.                     err=icPrefNotFoundErr;
  991.                 else {
  992.                     GetResInfo(prefh,&junk_id,&junk_type,key);
  993.                     err=ResError();
  994.                 }
  995.                 UseResFile(old_refnum);
  996.             }
  997.         }
  998.     }
  999.     
  1000.     if (prefh!=(Handle)0)
  1001.         ReleaseResource(prefh);
  1002.     
  1003.     return err;
  1004. }
  1005.  
  1006. ICError ICRDeletePref(ICRRecord* inst,StringPtr key){
  1007.     ICError err;
  1008.     Handle prefh;
  1009.     short old_refnum;
  1010.     
  1011.     err=ICRCheckInside(inst);
  1012.     if ((err==noErr)&&(key[0]==0))
  1013.         err=paramErr;
  1014.     
  1015.     if (err==noErr){
  1016.         if (inst->config_refnum==0)
  1017.             err=icPrefNotFoundErr;
  1018.         else {
  1019.             old_refnum=CurResFile();
  1020.             UseResFile(inst->config_refnum);
  1021.             err=ResError();
  1022.             if (err==noErr){
  1023.                 SetResLoad(false);
  1024.                 prefh=Get1NamedResource(kRes_Code,key);
  1025.                 err=ResError();
  1026.                 SetResLoad(true);
  1027.                 if (prefh==(Handle)0)
  1028.                     err=icPrefNotFoundErr;
  1029.                 else {
  1030.                     RmveResource(prefh);
  1031.                     DisposeHandle(prefh);
  1032.                     err=ResError();
  1033.                 }
  1034.                 UseResFile(old_refnum);
  1035.             }
  1036.         }
  1037.     }
  1038.     
  1039.     return err;
  1040. }
  1041.  
  1042. ICError ICREnd(ICRRecord* inst){
  1043.     ICError err;
  1044.     
  1045.     err=ICRCheckInside(inst);
  1046.     ICRCloseIfOpen(inst);
  1047.     
  1048.     return err;
  1049. }
  1050.  
  1051. ICError ICRDefaultFileName(ICRRecord* inst,StringPtr name){
  1052.     Str63 lname=kICDefaultFileName;
  1053.     
  1054.     BlockMoveData(lname,name,lname[0]+1);
  1055.     
  1056.     return noErr;
  1057. }
  1058.  
  1059. ICError ICREditPreferences(ICRRecord* inst,StringPtr key){
  1060.     ICError err;
  1061.     
  1062.     if (!inst->have_config_file)
  1063.         return bdNamErr;
  1064.     
  1065.     return EditPreferences(key,&(inst->config_file));
  1066. }
  1067.  
  1068. /*
  1069.     URL Parsing Algorithm
  1070.  
  1071.     1. if there is a selection skip to step 4
  1072.     2. expand selection to end of word (never skip an angle bracket though)
  1073.     3. if either end has an angle bracket then expand other end to search for angle bracket
  1074.     4. strip trailing and leading whitespace
  1075.     5. strip whitespace CR whitespace
  1076.     6. off < > if necessary
  1077.     7. remove leading URL:
  1078.     8. extract protocol by looking forwards for :
  1079.     9. if no protocol then prepend "hint:"
  1080. */
  1081.  
  1082. Boolean __URL_SpecStartChar(char ch){
  1083.     switch (ch){
  1084.         case ' ':
  1085.         case '<':
  1086.         case 9:
  1087.         case 13:
  1088.             return true;
  1089.         default:
  1090.             return false;
  1091.     }
  1092. }
  1093.  
  1094. Boolean __URL_SpecEndChar(char ch){
  1095.     switch (ch){
  1096.         case ' ':
  1097.         case '>':
  1098.         case 9:
  1099.         case 13:
  1100.             return true;
  1101.         default:
  1102.             return false;
  1103.     }
  1104. }
  1105.  
  1106. ICError ExpandSelection(char* datap,long len,long* selStart,long* selEnd){
  1107.     ICError err=noErr;
  1108.     Boolean found;
  1109.     
  1110.     // expand leading selection backwards looking for word break
  1111.     while ((*selStart>0)&&(!__URL_SpecStartChar(datap[(*selStart)-1])))
  1112.         (*selStart)--;
  1113.     if ((*selStart>0)&&(datap[(*selStart)-1]=='<'))
  1114.         (*selStart)--;
  1115.     
  1116.     // expand trailing selection forwards looking for word break
  1117.     while ((*selEnd<len)&&(!__URL_SpecEndChar(datap[*selEnd])))
  1118.         (*selEnd)++;
  1119.     if ((*selEnd<len)&&(datap[*selEnd]=='>'))
  1120.         (*selEnd)++;
  1121.     
  1122.     // if first char was a < then expand trailing selection to meet matching >
  1123.     if ((datap[*selStart]=='<')&&(datap[(*selEnd)-1]!='>')){
  1124.         while ((datap[(*selEnd)-1]!='>')&&((*selEnd)-1<=len))
  1125.             (*selEnd)++;
  1126.         
  1127.         // now either a match or at end of len
  1128.         if (datap[(*selEnd)-1]!='>')
  1129.             return icNoURLErr;
  1130.     }
  1131.     
  1132.     // if last char was a > then expand leading selection to meet matching <
  1133.     if ((datap[*selEnd]=='>')&&(datap[*selStart]!='<')){
  1134.         while ((datap[*selStart]!='<')&&(*selStart>=0))
  1135.             (*selStart)--;
  1136.         
  1137.         // now either a match or at end of len
  1138.         if (datap[*selStart]!='<')
  1139.             return icNoURLErr;
  1140.     }
  1141.     
  1142.     return err;
  1143. }
  1144.  
  1145. Boolean SpaceTab(char ch){
  1146.     if ((ch==' ')||(ch==9))
  1147.         return true;
  1148.     return false;
  1149. }
  1150.  
  1151. Boolean SpaceTabRet(char ch){
  1152.     if (ch==13)
  1153.         return true;
  1154.     return SpaceTab(ch);
  1155. }
  1156.  
  1157. ICError ShrinkSelection(char* datap,long len,long* selStart,long* selEnd){
  1158.     if (SpaceTab(datap[*selStart]))
  1159.         while (SpaceTab(datap[*selStart]))
  1160.             (*selStart)++;
  1161.     if (SpaceTab(datap[(*selEnd)-1]))
  1162.         while (SpaceTab(datap[(*selEnd)-1]))
  1163.             (*selEnd)--;
  1164.     
  1165.     return noErr;
  1166. }
  1167.  
  1168. ICError StripReturns(Handle urlh){
  1169.     ICError err;
  1170.     long srcsize,srcndx,dstndx;
  1171.     char* buf;
  1172.     SignedByte s;
  1173.     
  1174.     srcsize=GetHandleSize(urlh);
  1175.     err=MemError();
  1176.     if (srcsize==0){
  1177.         if (err!=noErr)
  1178.             return err;
  1179.         
  1180.         return icNoURLErr;
  1181.     }
  1182.     
  1183.     srcndx=0;
  1184.     dstndx=0;
  1185.     
  1186.     s=HGetState(urlh);
  1187.     HLock(urlh);
  1188.     buf=(char*)(*urlh);
  1189.     
  1190.     // skip down the buffer copying src to dst except when meeting cr
  1191.     while (srcndx<srcsize){
  1192.         if (buf[srcndx]==13){
  1193.             // move dstndx back to point to previous non-whitespace
  1194.             while ((dstndx>0)&&(SpaceTab(buf[dstndx-1])))
  1195.                 dstndx--;
  1196.             // move srcndx forwards to next non-whitespace
  1197.             while ((srcndx<srcsize)&&(SpaceTabRet(buf[srcndx])))
  1198.                 srcndx++;
  1199.         }
  1200.         
  1201.         if (srcndx<srcsize){
  1202.             // copy byte from src to dest
  1203.             buf[dstndx]=buf[srcndx];
  1204.             srcndx++;
  1205.             dstndx++;
  1206.         }
  1207.     }
  1208.     
  1209.     HSetState(urlh,s);
  1210.     
  1211.     // resize the handle to the number of bytes that we copied
  1212.     SetHandleSize(urlh,dstndx);
  1213.     err=MemError();
  1214.     
  1215.     return err;
  1216. }
  1217.  
  1218. ICError ICRParseURL(ICRRecord* inst,StringPtr hint,Ptr data,long len,long* selStart,long* selEnd,Handle urlh){
  1219.     char* datap=(char*)data;
  1220.     Str31 tmp="\pURL:";
  1221.     long junklong;
  1222.     long ndx;
  1223.     ICError err=noErr;
  1224.     
  1225.     if ((data==(Ptr)0)||(urlh==(Handle)0)||(*urlh==(Ptr)0)||(len<=0)||(*selStart<0)||(*selEnd<0)||(*selStart>len)||(*selEnd>len)||(*selStart>*selEnd))
  1226.         return paramErr;
  1227.     
  1228.     if (*selStart==*selEnd)
  1229.         err=ExpandSelection(datap,len,selStart,selEnd);
  1230.     if (err==noErr) // remove leading and trailing whitespace
  1231.         err=ShrinkSelection(datap,len,selStart,selEnd);
  1232.     
  1233.     if ((err==noErr)&&(*selStart>=*selEnd))
  1234.         return icNoURLErr;
  1235.     
  1236.     err=PtrToXHand((Ptr)&(datap[*selStart]),urlh,(*selEnd)-(*selStart));
  1237.     if (err==noErr)
  1238.         err=StripReturns(urlh);
  1239.     
  1240.     if (err==noErr){
  1241.         // strip any enclosing < >
  1242.         char* buf;
  1243.         long bsize=GetHandleSize(urlh);
  1244.         SignedByte s=HGetState(urlh);
  1245.         Boolean doTrim=false;
  1246.         
  1247.         HLock(urlh);
  1248.         buf=(char*)(*urlh);
  1249.         
  1250.         if ((buf[0]=='<')&&(buf[bsize-1]=='>')){
  1251.             doTrim=true;
  1252.         }
  1253.         
  1254.         HSetState(urlh,s);
  1255.         
  1256.         if (doTrim){
  1257.             SetHandleSize(urlh,bsize-1);
  1258.             HUnlock(urlh);
  1259.             // unlock before the munger call
  1260.             Munger(urlh,0,(Ptr)0,1,(Ptr)-1,0);
  1261.             HSetState(urlh,s);
  1262.         }
  1263.         
  1264.         // trim off leading "\pURL:"
  1265.         HLock(urlh);
  1266.         if ((GetHandleSize(urlh)>tmp[0])&&(IUMagIDString(*urlh,&(tmp[1]),tmp[0],tmp[0])==0)){
  1267.             HUnlock(urlh);
  1268.             Munger(urlh,0,(Ptr)0,tmp[0],(Ptr)-1,0);
  1269.         }
  1270.         HSetState(urlh,s);
  1271.         
  1272.         // search for protocol
  1273.         tmp[0]=1;tmp[1]=':';
  1274.         HUnlock(urlh);
  1275.         ndx=Munger(urlh,0,&(tmp[1]),1,(Ptr)0,0);
  1276.         if ((ndx<0)||(ndx>255)){
  1277.             // failed to find a colon in first 256 bytes,prepend "hint:" to url
  1278.             if (hint[0]==0)
  1279.                 err=icNoURLErr;
  1280.             else {
  1281.                 Munger(urlh,0,(Ptr)0,0,&(hint[1]),hint[0]);
  1282.                 err=MemError();
  1283.             }
  1284.         }
  1285.         HSetState(urlh,s);
  1286.     }
  1287.     return err;
  1288. }
  1289.  
  1290. ICError ICRLaunchURL(ICRRecord* inst,StringPtr hint,Ptr data,long len,long* selStart,long* selEnd){
  1291.     ICError err;
  1292.     Handle urlh;
  1293.     ICAppSpec helper;
  1294.     Str255 scheme;
  1295.     Str255 temp=kICHelper;
  1296.     long junk_attr;
  1297.     long size;
  1298.     
  1299.     urlh=NewHandle(0);
  1300.     err=MemError();
  1301.     
  1302.     if (err==noErr)
  1303.         err=ICRParseURL(inst,hint,data,len,selStart,selEnd,urlh);
  1304.     else 
  1305.         urlh=(Handle)0;
  1306.     
  1307.     if (err==noErr)
  1308.         err=FindScheme(urlh,scheme);
  1309.     
  1310.     if (err==noErr){
  1311.         size=sizeof(ICAppSpec);
  1312.         BlockMoveData(scheme,(Ptr)&(temp[temp[0]+1]),scheme[0]);
  1313.         temp[0]+=scheme[0];
  1314.         err=ICRGetPref(inst,temp,&junk_attr,(Ptr)(&helper),&size);
  1315.     }
  1316.     
  1317.     if (err==noErr)
  1318.         err=LaunchURL(helper.fCreator,urlh);
  1319.     
  1320.     if (urlh!=(Handle)0)
  1321.         DisposeHandle(urlh);
  1322.     
  1323.     return err;
  1324. }
  1325.  
  1326. void UnpackCopyString(Ptr* p,StringPtr s){
  1327.     short len;
  1328.     
  1329.     // calc the len of the current pascal string pointed to by p
  1330.     len=((**p) & 0x00ff) +1;
  1331.     
  1332.     // copy the string in the buffer to s
  1333.     BlockMoveData(*p,s,len);
  1334.     
  1335.     // move the pointer to the start of the next pascal string
  1336.     *p=(Ptr)((*p)+len);
  1337. }
  1338.  
  1339. // Internal Mapping Subs
  1340. OSErr UnpackEntry(Handle entries,long pos,ICMapEntry* entry,long* user_length){
  1341.     // WARNING: Depends very much on the exact format of ICMapEntry!
  1342.     Ptr org,p;
  1343.     long maxsize;
  1344.     OSErr err=noErr;
  1345.     
  1346.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)-6))
  1347.         return paramErr;
  1348.     
  1349.     p=(Ptr)((*entries)+pos);
  1350.     maxsize=GetHandleSize(entries);
  1351.     org=p;
  1352.     
  1353.     BlockMoveData(p,(Ptr)entry,6);
  1354.     
  1355.     if ((entry->fixed_length!=ICmap_fixed_length)||(entry->fixed_length>entry->total_length)||(entry->total_length>maxsize))
  1356.         return badExtResource;
  1357.     
  1358.     BlockMoveData(p,entry,entry->fixed_length);
  1359.     p=(Ptr)(p+entry->fixed_length);
  1360.     UnpackCopyString(&p,entry->extension);
  1361.     UnpackCopyString(&p,entry->creator_app_name);
  1362.     UnpackCopyString(&p,entry->post_app_name);
  1363.     UnpackCopyString(&p,entry->MIME_type);
  1364.     UnpackCopyString(&p,entry->entry_name);
  1365.     
  1366.     *user_length=entry->total_length-(p-org);
  1367.     
  1368.     return err;
  1369. }
  1370.  
  1371. // a fast version of ICRGetEntry doesn't return all of the strings for the entry
  1372. // WARNING: Depends very much on the exact format of ICMapEntry!
  1373. OSErr FastGetEntry(Handle entries,long pos,ICMapEntry* entry){
  1374.     Ptr org,p;
  1375.     long maxsize;
  1376.     OSErr err=noErr;
  1377.     
  1378.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)-6))
  1379.         return paramErr;
  1380.     
  1381.     p=(Ptr)((*entries)+pos);
  1382.     maxsize=GetHandleSize(entries);
  1383.     BlockMoveData(p,entry,6);
  1384.     
  1385.     if ((entry->fixed_length!=ICmap_fixed_length)||(entry->fixed_length>entry->total_length)||(entry->total_length>maxsize))
  1386.         return badExtResource;
  1387.     
  1388.     BlockMoveData(p,entry,entry->fixed_length);
  1389.     p=(Ptr)(p+entry->fixed_length);
  1390.     BlockMoveData(p,entry->extension,(((*p)&0x00ff)+1));
  1391.     return err;
  1392. }
  1393.  
  1394. void PackCopyString(ICMapEntry* entry,Ptr p,StringPtr s){
  1395.     
  1396.     BlockMoveData(s,(Ptr)(p+entry->total_length),s[0]+1);
  1397.     entry->total_length+=s[0]+1;
  1398. }
  1399.  
  1400. void PackEntry(ICMapEntry* entry,Ptr p,long user_length){
  1401.     Ptr a,b;
  1402.     
  1403.     entry->version=0;
  1404.     
  1405.     a=(Ptr)&(entry->extension);
  1406.     b=(Ptr)entry;
  1407.     
  1408.     entry->fixed_length=a-b;
  1409.     entry->total_length=entry->fixed_length;
  1410.     
  1411.     PackCopyString(entry,p,entry->extension);
  1412.     PackCopyString(entry,p,entry->creator_app_name);
  1413.     PackCopyString(entry,p,entry->post_app_name);
  1414.     PackCopyString(entry,p,entry->MIME_type);
  1415.     PackCopyString(entry,p,entry->entry_name);
  1416.     
  1417.     entry->total_length+=user_length;
  1418.     
  1419.     BlockMoveData(entry,p,entry->fixed_length);
  1420. }
  1421.  
  1422. short GetShort(Ptr P){
  1423.     unsigned char* p=(unsigned char*)P;
  1424.     short val=0;
  1425.     
  1426.     val=p[0];
  1427.     val <<= 8;
  1428.     val+=p[1];
  1429.     
  1430.     return val;
  1431. }
  1432.  
  1433. char UpCase(char ch){
  1434.     
  1435.     if ((ch>='a')&&(ch<='z'))
  1436.         return (ch-'a')+'A';
  1437.     
  1438.     return ch;
  1439. }
  1440.  
  1441. Boolean IsExtensionVar(StringPtr name,StringPtr ext){
  1442.     short pn,pe;
  1443.     
  1444.     if (name[0]>=ext[0]){
  1445.         pn=name[0]-ext[0]+1;
  1446.         pe=1;
  1447.         
  1448.         while (pe<=ext[0]){
  1449.             if (UpCase(name[pn])!=UpCase(ext[pe]))
  1450.                 break;
  1451.             
  1452.             pn++;
  1453.             pe++;
  1454.         }
  1455.         
  1456.         return pe>ext[0];
  1457.     }
  1458.     return false;
  1459. }
  1460.  
  1461. // Low Level Mapping Routines
  1462.  
  1463. ICError ICRCountMapEntries(ICRRecord* inst,Handle entries,long* count){
  1464.     Ptr p;
  1465.     long pos;
  1466.     short size;
  1467.     long hsize;
  1468.     
  1469.     if ((entries==(Handle)0)||(*entries==(Ptr)0))
  1470.         return paramErr;
  1471.     
  1472.     p=*entries;
  1473.     pos=0L;
  1474.     *count=0;
  1475.     hsize=GetHandleSize(entries);
  1476.     while (pos<hsize){
  1477.         size=GetShort(p); // extract the total_length value from the current pointer
  1478.         pos+=size; // add it to the pos offset
  1479.         p+=size; // add it to the pointer
  1480.         (*count)++; // increment the count
  1481.     }
  1482.     
  1483.     return noErr;
  1484. }
  1485.  
  1486. ICError ICRGetIndMapEntry(ICRRecord* inst,Handle entries,long ndx,long* pos,ICMapEntry* entry){
  1487.     ICError err;
  1488.     Ptr p;
  1489.     long i;
  1490.     short size;
  1491.     long hsize;
  1492.     
  1493.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(ndx<0))
  1494.         return paramErr;
  1495.     
  1496.     p=(Ptr)*entries;
  1497.     *pos=0;
  1498.     hsize=GetHandleSize(entries);
  1499.     
  1500.     while ((ndx>1)&&(*pos<hsize)){
  1501.         size=GetShort(p); // extract the total_length value from the current pointer
  1502.         *pos+=size; // add the size to the pos offset
  1503.         p+=size; // add the size to the pointer
  1504.         ndx--; // decrease the index for the entry
  1505.     }
  1506.     
  1507.     return ICRGetMapEntry(inst,entries,*pos,entry);
  1508. }
  1509.  
  1510. ICError ICRGetMapEntry(ICRRecord* inst,Handle entries,long pos,ICMapEntry* entry){
  1511.     ICError err;
  1512.     long user_length;
  1513.     
  1514.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)))
  1515.         return paramErr;
  1516.     
  1517.     return UnpackEntry(entries,pos,entry,&user_length);
  1518. }
  1519.  
  1520. ICError ICRSetMapEntry(ICRRecord* inst,Handle entries,long pos,ICMapEntry* entry){
  1521.     ICError err;
  1522.     ICMapEntry e,oldentry;
  1523.     long user_length,source_length;
  1524.     
  1525.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)))
  1526.         return paramErr;
  1527.     
  1528.     err=UnpackEntry(entries,pos,&oldentry,&user_length);
  1529.     
  1530.     if (err==noErr){
  1531.         PackEntry(entry,(Ptr)&e,user_length);
  1532.         source_length=oldentry.total_length-user_length;
  1533.         
  1534.         if (user_length<8){ // hack to remove alignment bytes from previous version
  1535.             source_length=oldentry.total_length;
  1536.             e.total_length=e.total_length-user_length;
  1537.             user_length=0;
  1538.         }
  1539.         Munger(entries,pos,(Ptr)0,source_length,&e,e.total_length-user_length);
  1540.         err=MemError();
  1541.     }
  1542.     
  1543.     return err;
  1544. }
  1545.  
  1546. ICError ICRDeleteMapEntry(ICRRecord* inst,Handle entries,long pos){
  1547.     ICError err;
  1548.     ICMapEntry entry;
  1549.     long user_length;
  1550.     
  1551.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>=GetHandleSize(entries)))
  1552.         return paramErr;
  1553.     
  1554.     err=UnpackEntry(entries,pos,&entry,&user_length);
  1555.     
  1556.     if (err==noErr){
  1557.         Munger(entries,pos,(Ptr)0,entry.total_length,(Ptr)-1,0);
  1558.         err=MemError();
  1559.     }
  1560.     
  1561.     return err;
  1562. }
  1563.  
  1564. ICError ICRAddMapEntry(ICRRecord* inst,Handle entries,ICMapEntry* entry){
  1565.     ICError err;
  1566.     ICMapEntry tmp_entry;
  1567.     
  1568.     if ((entries==(Handle)0)||(*entries==(Ptr)0))
  1569.         return paramErr;
  1570.     
  1571.     PackEntry(entry,(Ptr)&tmp_entry,0);
  1572.     
  1573.     return PtrAndHand(&tmp_entry,entries,entry->total_length);
  1574. }
  1575.  
  1576. // High Level Mapping Subs
  1577.  
  1578. ICError ICRMapEntriesFilename(ICRRecord* inst,Handle entries,StringPtr filename,ICMapEntry* entry){
  1579.     // Implementation lifted directly from Space Aliens
  1580.     ICError err;
  1581.     short longest_len;
  1582.     long posndx,found_pos;
  1583.     
  1584.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(filename[0]==0))
  1585.         return paramErr;
  1586.     
  1587.     // loop through the entries
  1588.     // looking for the longest match
  1589.     
  1590.     longest_len=0;
  1591.     posndx=0;
  1592.     
  1593.     while (FastGetEntry(entries,posndx,entry)==noErr){
  1594.         // the entry matches if not_incoming flag bit is clear,
  1595.         // it's longer than the previous match, it's longer than the filename,
  1596.         // and it matches the last N chars of the filename.
  1597.         
  1598.         if ((entry->extension[0]>longest_len)&&(!(entry->flags&ICmap_not_incoming_mask))&&(IsExtensionVar(filename,entry->extension))){
  1599.             // record the new longest entry
  1600.             found_pos=posndx;
  1601.             longest_len=entry->extension[0];
  1602.         }
  1603.         // increment posndx so that we get the next entry the next time around the loop
  1604.         posndx+=entry->total_length;
  1605.     }
  1606.     
  1607.     if (longest_len==0)
  1608.         return icPrefNotFoundErr;
  1609.     
  1610.     return ICRGetMapEntry(inst,entries,found_pos,entry);
  1611. }
  1612.  
  1613. ICError ICRMapEntriesTypeCreator(ICRRecord* inst,Handle entries,OSType fType,OSType fCreator,StringPtr filename,ICMapEntry* entry){
  1614.     ICError err;
  1615.     long posndx,found_pos,match_weight,best_weight;
  1616.     
  1617.     if ((entries==(Handle)0)||(*entries==(Ptr)0))
  1618.         return paramErr;
  1619.     
  1620.     posndx=0L;
  1621.     best_weight=-1L;
  1622.     
  1623.     while (FastGetEntry(entries,posndx,entry)==noErr){
  1624.         if (!(entry->flags&ICmap_not_outgoing_mask)){
  1625.             if (entry->file_type==fType){
  1626.                 match_weight=entry->file_creator==fCreator;
  1627.                 if (IsExtensionVar(filename,entry->extension)){
  1628.                     match_weight+=2*(entry->extension[0]);
  1629.                 }
  1630.                 if (match_weight>best_weight){
  1631.                     // record the new longest entry
  1632.                     found_pos=posndx;
  1633.                     best_weight=match_weight;
  1634.                 }
  1635.             }
  1636.         }
  1637.         posndx+=entry->total_length;
  1638.     }
  1639.     
  1640.     if (best_weight==-1)
  1641.         return icPrefNotFoundErr;
  1642.     
  1643.     return ICRGetMapEntry(inst,entries,found_pos,entry);
  1644. }
  1645.  
  1646. // High Level Mapping Routines
  1647.  
  1648. ICError ICRMapFilename(ICRRecord* inst,StringPtr filename,ICMapEntry* entry){
  1649.     ICError err;
  1650.     Handle entries;
  1651.     ICAttr junk_attr;
  1652.     
  1653.     if (filename[0]==0)
  1654.         return paramErr;
  1655.     
  1656.     err=ICRGetPrefHandle(inst,kICMapping,&junk_attr,&entries);
  1657.     if (err==noErr){
  1658.         err=ICRMapEntriesFilename(inst,entries,filename,entry);
  1659.         DisposeHandle(entries);
  1660.     }
  1661.     
  1662.     return err;
  1663. }
  1664.  
  1665. ICError ICRMapTypeCreator(ICRRecord* inst,OSType fType,OSType fCreator,StringPtr filename,ICMapEntry* entry){
  1666.     ICError err;
  1667.     Handle entries;
  1668.     ICAttr junk_attr;
  1669.     
  1670.     err=ICRGetPrefHandle(inst,kICMapping,&junk_attr,&entries);
  1671.     if (err==noErr){
  1672.         err=ICRMapEntriesTypeCreator(inst,entries,fType,fCreator,filename,entry);
  1673.         DisposeHandle(entries);
  1674.     }
  1675.     
  1676.     return err;
  1677. }
  1678.  
  1679.  
  1680.  
  1681.  
  1682.  
  1683.  
  1684.  
  1685.  
  1686.  
  1687.  
  1688.